package com.yutons.encrypt.interceptor;

import com.yutons.encrypt.config.MpEncryptProperties;
import com.yutons.encrypt.cryptor.IMpEncrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @Title 参数插件ParameterInterceptor
 * @Author yutons
 * @Date 2024-08-18 23:40
 * @Desc 切入mybatis设置参数时对敏感数据进行加密
 * Intercepts注解
 * 使用mybatis插件时需要定义签名
 * type标识需要切入的Handler
 * method表示要要切入的方法
 */
@Slf4j
@Intercepts({
	@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
})
public class MpEncryptParameterInterceptor implements Interceptor {
	private final IMpEncrypt customEncryptor;
	private final MpEncryptProperties properties;

	public MpEncryptParameterInterceptor(IMpEncrypt customEncryptor, MpEncryptProperties properties) {
		this.customEncryptor = customEncryptor;
		this.properties = properties;
	}

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		//@Signature 指定了 type= parameterHandler 后，这里的 invocation.getTarget() 便是parameterHandler
		//若指定ResultSetHandler ，这里则能强转为ResultSetHandler
		ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
		Object parameterObject = null;
		try {
			// 获取参数对像，即 mapper 中 paramsType 的实例
			Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
			parameterField.setAccessible(true);
			//取出实例
			parameterObject = parameterField.get(parameterHandler);
		} catch (Exception e) {
			parameterObject = parameterHandler.getParameterObject();
		}


		if (properties.getEnabled() && parameterObject != null) {
			// 判断是否是mybatis的MapperMethod.ParamMap，如果是，则需求取对象中的et实体类
			if (parameterObject instanceof MapperMethod.ParamMap) {
				// 基于mybatis-plus的字段加密
				// 忽略加密的key
				List<String> keys = new ArrayList<>();
				keys.add("param1");
				MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameterObject;
				if (paramMap != null) {
					for (Object key : paramMap.keySet()) {
						// 忽略加密param的key
						if (!keys.contains(key)) {
							Object mapParameterObject = paramMap.get(key);
							if (mapParameterObject != null) {
								customEncryptor.encrypt(mapParameterObject);
								paramMap.put(key, mapParameterObject);
							}
						}
					}
				}
			} else {
				customEncryptor.encrypt(parameterObject);
			}
		}
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
//		 return Interceptor.super.plugin(target);
		return target instanceof ParameterHandler ? Plugin.wrap(target, this) : target;
	}

	@Override
	public void setProperties(Properties properties) {
//		 Interceptor.super.setProperties(properties);
	}
}
